package com.hdd.utils.wxUtils;

import com.hdd.model.wx.*;
import com.hdd.utils.UUIDGenerator;
import com.hdd.utils.http.HttpClient;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.stereotype.Component;

import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyStore;
import java.util.*;


/**
 *
* @ClassName: WeiXinPayService
* @Description: TODO 微信支付
* @author yangjian
* @date 2020年10月9日 下午2:12:06
*
 */
@Component
public class WeiXinPayService {

    private static final Logger logger = LoggerFactory.getLogger(WeiXinPayService.class);

    @Value("${wx.appid}")
    private String appid;// 小程序id
    @Value("${wx.mch_id}")
    private String mch_id;// 微信商户号
    @Value("${wx.unifiedorder_url}")
    private String unifiedorder_url;// 统一下单地址
    @Value("${wx.query_unifiedorder_url}")
    private String query_unifiedorder_url; //查询统一下单结果地址
    @Value("${wx.notify_url}")
    private String notify_url;// 回调通知
    //@Value("${wx.key}")
    private String key = "E3C83EB7424861B37C0F77E09C2457D6";// 商户平台秘钥key
    @Value("${wx.transfers_url}")
    private String transfers_url;//企业向零钱付款地址
    @Value("${wx.p12Path}")
    private String p12Path;
    @Value("${wx.password}")
    private String password;

    private static SSLConnectionSocketFactory sslsf;


    private void getSslf(){
        try {
        /*
            appid=wxProperties.getAppid();
            mch_id=wxProperties.getMch_id();
            unifiedorder_url=wxProperties.getUnifiedorder_url();
            notify_url=wxProperties.getNotify_url();
            key=wxProperties.getKey();
            transfers_url=wxProperties.getTransfers_url();
            p12Path=wxProperties.getP12Path();
            password=wxProperties.getPassword();
            */
            KeyStore keyStore = KeyStore.getInstance("PKCS12");
            FileInputStream instream = new FileInputStream(new File(p12Path));
            keyStore.load(instream, password.toCharArray());
            // Trust own CA and all self-signed certs
            SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, password.toCharArray()).build();
            // Allow TLSv1 protocol only
            sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
        } catch (Exception e) {
            logger.error("sslInit error:{}", e);
        }
    }



    // 统一下单
    public Result<Map<String, Object>> unifiedorder(String orderNum, int amount, String openId, String ip,String notify) {
        Result<Map<String, Object>> payResult = null;
        UnifiedorderModel model = new UnifiedorderModel();
        model.setAppid(appid);
        model.setMch_id(mch_id);
        model.setOpenid(openId);
        model.setBody("画多多-充值");
        model.setNonce_str(UUIDGenerator.generate());
        model.setNotify_url(notify_url+notify);
        model.setOut_trade_no(orderNum);
        model.setTotal_fee(amount);// 单位：分
        model.setSpbill_create_ip("192.168.3.193");
        model.setSign(sign(model));
        String xml = WeiXinPayXmlParser.BeanToXml(model);
        logger.info("微信统一下单参数：{}", xml);
        String resultXml = HttpClient.postXml(unifiedorder_url, xml);
        logger.info("结果：{}", resultXml);
        CheckSign checkSign = checkSign(resultXml, UnifiedorderRepModel.class);
        if (checkSign.isSignOk()) {
            UnifiedorderRepModel repModel = (UnifiedorderRepModel) checkSign.getData();
            // 再次签名
            Map<String, Object> toSignMap = new HashMap<>();
            toSignMap.put("appId", appid);
            toSignMap.put("timeStamp", new Date().getTime());
            toSignMap.put("nonceStr", UUIDGenerator.generate());
            toSignMap.put("package", "prepay_id=" + repModel.getPrepay_id());
            toSignMap.put("signType", "MD5");
            String paySign = sign(toSignMap);
            toSignMap.put("paySign", paySign);
            //小程序端调起微信支付后，用户并未支付，选择退出支付，此时使用该字段调用更改支付状态
            toSignMap.put("orderNum", orderNum);
            payResult = new Result<Map<String, Object>>(toSignMap);
        } else {
            payResult = new Result<Map<String, Object>>(false);
        }
        return payResult;
    }

    //查询统一下单的订单结果
    public Map<String,Object> queryUnifiedorder(String orderNum){
//        Map<String, Object> paramMap=new HashMap<String, Object>();
//        paramMap.put("appid", appid);
//        paramMap.put("mch_id", mch_id);
//        paramMap.put("out_trade_no", orderNum);
//        paramMap.put("nonce_str", UUIDGenerator.generate());
//        paramMap.put("sign", sign(paramMap));

        QueryUnifiedorderModel model = new QueryUnifiedorderModel();
        model.setAppid(appid);
        model.setMch_id(mch_id);
        model.setOut_trade_no(orderNum);
        model.setNonce_str(UUIDGenerator.generate());
        model.setSign(sign(model));
        String xml = WeiXinPayXmlParser.BeanToXml(model);
        logger.info("微信统一下单查询参数：{}", xml);
        String resultXml = HttpClient.postXml(query_unifiedorder_url, xml);
        Map<String, Object> resultMap=WeiXinPayXmlParser.xmlFormatStringToMap(resultXml);
        return resultMap;
    }


    //企业向零钱付款
    public TranferRepModel transfers(String orderNum, String openId, int amount, String ip) {
        Result<TranferRepModel> payResult = null;
        TranferModel tranferModel = new TranferModel();
        tranferModel.setMch_appid(appid);
        tranferModel.setMchid(mch_id);
        tranferModel.setNonce_str(UUIDGenerator.generate());
        tranferModel.setPartner_trade_no(orderNum);
        tranferModel.setOpenid(openId);
        tranferModel.setCheck_name("NO_CHECK");
        tranferModel.setAmount(amount);
        tranferModel.setDesc("画多多-余额提现");
        tranferModel.setSpbill_create_ip("ip");
        tranferModel.setSign(sign(tranferModel));
        String xml = WeiXinPayXmlParser.BeanToXml(tranferModel);
        logger.info("微信企业向零钱付款参数：{}", xml);
        String resultXml = this.customSSlHttpPost(transfers_url, xml);
        TranferRepModel tranferRepModel =  WeiXinPayXmlParser.XmlToBean(resultXml, TranferRepModel.class);
        return tranferRepModel;
    }

  //验证订单真实性
    public boolean verifyOrder(Map<String,Object> map){
        if(!appid.equals(map.get("appid").toString().trim())){
            return false;
        }
        if(!mch_id.equals(map.get("mch_id").toString().trim())){
            return false;
        }
        return true;
    }

    // 签名
    private String sign(Object bean) {
        Map<String, Object> params = null;
        if (bean instanceof Map) {
            params = (Map<String, Object>) bean;
        } else {
            params = BeanMap.create(bean);
        }
        // 排序
        TreeMap<String, Object> srotMap = new TreeMap<String, Object>(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.compareTo(o2);
            }
        });
        if (params != null && !params.isEmpty()) {
            for (String key : params.keySet()) {
                if (params.get(key) != null) {
                    srotMap.put(key, params.get(key));
                }
            }
        }
        // 1.拼装querystring
        StringBuilder queryData = new StringBuilder();
        if (srotMap != null && !srotMap.isEmpty()) {
            for (Map.Entry<String, Object> entry : srotMap.entrySet()) {
                queryData.append(entry.getKey()).append("=");
                queryData.append(entry.getValue().toString());
                queryData.append("&");
            }
            queryData.append("key=" + key);
        }
        String sign = MD5.MD5Encode(queryData.toString(), "utf-8");
        return sign.toUpperCase();
    }

    // 验签
    public CheckSign checkSign(String xml, Class modelClazz) {
        WeixinModel repModel = (WeixinModel) WeiXinPayXmlParser.XmlToBean(xml, modelClazz);
        String sign = repModel.getSign();
        repModel.setSign(null);
        String ourSign = sign(repModel);
        CheckSign checkSign = new CheckSign(sign.equals(ourSign), repModel);
        return checkSign;
    }


    //ssl自定义
    private String customSSlHttpPost(String url, String entity) {
        if(null==sslsf || "".equals(sslsf)){
            getSslf();
        }
        CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
        CloseableHttpResponse httpResponse = null;
        try {
            HttpPost httpPost = new HttpPost(url);
            StringEntity httpEntity = new StringEntity(entity, "utf-8");
            httpPost.setEntity(httpEntity);
            httpResponse = httpClient.execute(httpPost);
            if (httpResponse.getStatusLine().getStatusCode() == 200) {
                HttpEntity repEntity = httpResponse.getEntity();
                String result = EntityUtils.toString(repEntity, "utf-8");
                logger.info("微信支付返回：\r\n{}", result);
                return result;
            }
        } catch (Exception e) {
            logger.error("WeixinPayService.post error {}", e);
        } finally {
            try {
                httpResponse.close();
                httpClient.close();
            } catch (IOException e) {

            }
        }
        return null;
    }

    public static void main(String[] args) {
        Result<Map<String, Object>> payResult = new WeiXinPayService().unifiedorder("123abc", 1, "orCqD4vOw-8bliH57J7DmN-t_oIQ", "192.168.3.193", "/wx/payment/unifiedorderNotify");
       // System.out.println(payResult);
       // TranferRepModel payResult = new WeiXinPayService().transfers("sunchao123", "o80Wt4suCdLHo8sqLkXk2Kaqauy0", 400, "192.168.6.133");
        System.out.println(payResult.getMsg());
    }

}
